﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Configuration;
using System.Net;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;


namespace MasoQna.Infrastructure.Auth
{
    public abstract class AbstractConsumer : IAuthHandler
    {
        public void StartAuthentication()
        {
            var redirectParameters = CreateRedirectParameters();
            Uri callback = MessagingUtilities.GetRequestUrlFromContext().StripQueryArgumentsWithPrefix("oauth_");
            var request = Login.PrepareRequestUserAuthorization(callback, null, redirectParameters);
            Login.Channel.PrepareResponse(request).Send();
        }

        public bool FinishAuthenticaiton(out string providedUserId)
        {
            providedUserId = null;
            var response = Login.ProcessUserAuthorization();
            if (response == null)
            {
                return false;
            }

            providedUserId = GetUserId(response.ExtraData);
            return true;
        }

        private ServiceProviderDescription CreateServiceProviderDescription()
        {
            return new ServiceProviderDescription
            {
                RequestTokenEndpoint = new MessageReceivingEndpoint(RequestTokenEndPoint, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
                UserAuthorizationEndpoint = new MessageReceivingEndpoint(UserAuthorizationEndPoint, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
                AccessTokenEndpoint = new MessageReceivingEndpoint(AccessTokenEndPoint, HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
                TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
            };
        }

        private WebConsumer signInConsumer;

        public bool IsConsumerConfigured
        {
            get
            {
                return !string.IsNullOrEmpty(ConsumerKey) && !string.IsNullOrEmpty(ConsumerSecret);
            }
        }

        private WebConsumer Login
        {
            get
            {
                if (signInConsumer == null)
                {
                    signInConsumer = new WebConsumer(CreateServiceProviderDescription(), ShortTermUserSessionTokenManager);
                }

                return signInConsumer;
            }
        }

        private InMemoryTokenManager ShortTermUserSessionTokenManager
        {
            get
            {
                var store = HttpContext.Current.Session;
                var tokenManager = (InMemoryTokenManager)store["OAuth1ShortTermUserSessionTokenManager"];
                if (tokenManager == null)
                {
                    string consumerKey = ConsumerKey;
                    string consumerSecret = ConsumerSecret;
                    if (IsConsumerConfigured)
                    {
                        tokenManager = new InMemoryTokenManager(consumerKey, consumerSecret);
                        store["OAuth1ShortTermUserSessionTokenManager"] = tokenManager;
                    }
                    else
                    {
                        throw new InvalidOperationException("No OAuth consumer key and secret could be found in web.config AppSettings.");
                    }
                }

                return tokenManager;
            }
        }

        //이하는 구현할 때에 정의해야 할 사항들.

        protected string RequestTokenEndPoint { get; set; }
        protected string UserAuthorizationEndPoint { get; set; }
        protected string AccessTokenEndPoint { get; set; }
        protected string ConsumerKey { get; set; }
        protected string ConsumerSecret { get; set; }

        public virtual Dictionary<string, string> CreateRedirectParameters()
        {
            return new Dictionary<string, string>();
        }

        public abstract string GetUserId(IDictionary<string, string> responseExtraData);
        public abstract string ImagePath { get; }
    }
}